package com.exceptionHandler;

import com.alibaba.fastjson.JSONObject;
import com.dao.SystemExceptionLogMapper;
import com.exception.BusinessException;
import com.exception.LoginTimeOutException;
import com.exception.ServiceRuntimeException;
import com.log.LoggerFactory;
import com.model.SystemExceptionLog;
import com.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 统一异常处理
 */
@Slf4j
@ControllerAdvice
public class ServerExceptionHandler {

    protected Logger loggerError = LoggerFactory.getServerErrorLogger(ServerExceptionHandler.class);


    @Autowired
    private SystemExceptionLogMapper  systemExceptionLogMapper;

    //LoginTimeOutException
    @ExceptionHandler({LoginTimeOutException.class})
    @ResponseBody
    public String  handleLoginTimeOutException(HttpServletRequest request, HttpServletResponse response, Exception ex){
        ex.printStackTrace();
        Result<String> result=new Result(false,"登录超时，请重新登录！！！",null,101);
        String msg= ex.getMessage();
        String requrl="";
        Map<String,String[]> params=new HashMap<String,String[]>();
        requrl=request.getRequestURI();
        params=request.getParameterMap();
        Map<String,String> paramMap=new HashMap<String,String>();
        for(Map.Entry<String,String[]> param:params.entrySet()){
            String key=param.getKey();
            String[] value=param.getValue();
            paramMap.put(key, value.length==1?value[0]:JSONObject.toJSONString(value));

        }
        log.error("{\"url\":\"{}\",\"params\":{},\"exception\":{}}",requrl,JSONObject.toJSONString(paramMap),formatExceptionStr(ex));
        return JSONObject.toJSONString(result);
    }
    @ExceptionHandler({BusinessException.class})
    @ResponseBody
    public Result<String>  handleBusinessException(HttpServletRequest request, HttpServletResponse response, BusinessException ex){

        Result<String> result=new Result();
        String msg= ex.getMessage();
        String requrl="";
        Map<String,String[]> params=new HashMap<String,String[]>();
        requrl=request.getRequestURI();
        params=request.getParameterMap();
        Map<String,String> paramMap=new HashMap<String,String>();
        for(Map.Entry<String,String[]> param:params.entrySet()){
            String key=param.getKey();
            String[] value=param.getValue();
            paramMap.put(key, value.length==1?value[0]:JSONObject.toJSONString(value));

        }
        //异步方式把系统错误日志入库
        CompletableFuture.runAsync(()->recordSystemBusinessExceptionLog(ex)).toCompletableFuture();
        result.error(ex.getCode(),ex.getMessage(),ex.getContent());
        return result;
    }



    /**
     * 处理全局异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<String> handlerGlobalException(HttpServletRequest request, HttpServletResponse response, Exception ex, Model model){
        System.out.println("系统异常拦截处理");
        Result<String> result=new Result();
        String msg= "系统异常";
        String requrl="";
        Map<String,String[]> params=new HashMap<String,String[]>();
        requrl=request.getRequestURI();
        params=request.getParameterMap();
        Map<String,String> paramMap=new HashMap<String,String>();
        for(Map.Entry<String,String[]> param:params.entrySet()){
            String key=param.getKey();
            String[] value=param.getValue();
            paramMap.put(key, value.length==1?value[0]:JSONObject.toJSONString(value));

        }
        //异步方式把系统错误日志入库
        CompletableFuture.runAsync(()->recordSystemRuntimeExceptionLog(ex));
        loggerError.error("{\"url\":\"{}\",\"params\":{},\"exception\":{}}",requrl,JSONObject.toJSONString(paramMap),formatExceptionStr(ex));
        return result.error("系统异常") ;
    }

    private String formatExceptionStr(Exception e){
        if(e!=null){
            StringBuilder exceptionBuilder=new StringBuilder();
            exceptionBuilder.append("\n");
            exceptionBuilder.append(e.getMessage()+" \n");
            if(e.getStackTrace()!=null&&e.getStackTrace().length>0){
                for(StackTraceElement trace:e.getStackTrace()){
                    exceptionBuilder.append("\tat "+trace.toString()+" \n");
                }
            }
            return exceptionBuilder.toString();
        }else
            return null;
    }

    //异常入库逻辑

    private  void   recordSystemBusinessExceptionLog(Exception  inE){
        try{
            Date now=new Date();
            SystemExceptionLog  exceptionLog=new SystemExceptionLog();
            exceptionLog.setHappenTime(now);
            exceptionLog.setExceptionType(2);
            exceptionLog.setExceptionTypeName("业务异常");
            exceptionLog.setExceptionKeyWord(inE.getMessage());
            StackTraceElement[] stackTrace = inE.getCause().getStackTrace();
            StackTraceElement firstTrace= stackTrace[0];
            exceptionLog.setExceptionApi(firstTrace.getClassName());
            exceptionLog.setApiMethod(firstTrace.getMethodName());
            exceptionLog.setExceptionInfo(formatExceptionStr(inE));
            exceptionLog.setBody(JSONObject.toJSONString(inE));
            exceptionLog.setCreateTime(now);
            systemExceptionLogMapper.insert(exceptionLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    private  void   recordSystemRuntimeExceptionLog(Exception  inE){
        try{
            Date now=new Date();
            SystemExceptionLog exceptionLog=new SystemExceptionLog();
            exceptionLog.setHappenTime(now);
            exceptionLog.setExceptionType(1);
            exceptionLog.setExceptionTypeName("系统异常");
            exceptionLog.setExceptionKeyWord("系统运行时异常");
            StackTraceElement[] stackTrace =inE.getStackTrace();
            StackTraceElement firstTrace= stackTrace[0];
            exceptionLog.setExceptionApi(firstTrace.getClassName());
            exceptionLog.setApiMethod(firstTrace.getMethodName());
            exceptionLog.setExceptionInfo(formatExceptionStr(inE));
            exceptionLog.setBody(JSONObject.toJSONString(inE));
            exceptionLog.setCreateTime(now);
            systemExceptionLogMapper.insert(exceptionLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }



}
